library ieee;
use ieee.std_logic_1164.all;
use IEEE.NUMERIC_STD.all;
use work.typeDefinitions.all;

entity memHierarchy is
  port
    (
      --normal stuff
      clk    : in std_logic;
      nReset : in std_logic;

      --dcache
      halt          : in  std_logic;
      halt_out      : out std_logic;
      dMemRead      : in  std_logic;                       -- CPU side
      dMemWrite     : in  std_logic;                       -- CPU side
      dMemWait      : out std_logic;                       -- CPU side
      dMemAddr      : in  std_logic_vector (31 downto 0);  -- CPU side
      dMemDataRead  : out std_logic_vector (31 downto 0);  -- CPU side
      dMemDataWrite : in  std_logic_vector (31 downto 0);  -- CPU side

      iMemData : out std_logic_vector(31 downto 0);
      iMemRen  : in  std_logic;
      iMemWait : out std_logic;
      iMemAddr : in  std_logic_vector (31 downto 0);


      TxBusOp   : out memBusOp;
      TxBusAddr : out std_logic_vector(31 downto 0);
      TxBusResp : out memBusResp;
      TxBusData : out std_logic_vector(63 downto 0);
      RxBusOp   : in  memBusOp;
      RxBusAddr : in  std_logic_vector(31 downto 0);
      RxBusResp : in  memBusResp;
      RxBusData : in  std_logic_vector(63 downto 0);
      
      --linkreg
      lockAddr : in  std_logic_vector(31 downto 0);
      lockWEN  : in  std_logic;
      busOp    : in  memBusOp;
      busAddr  : in  std_logic_vector(31 downto 0);
      lockOut  : out std_logic_vector(31 downto 0);

      --"memory" side
      memAddr      : out std_logic_vector(15 downto 0);  -- mem address being read/written
      memWriteData : out std_logic_vector(31 downto 0);  -- mem data to be written
      memWEN       : out std_logic;     -- write enable
      memREN       : out std_logic;     -- read enable
      memReadData  : in  std_logic_vector(31 downto 0);  -- mem data to be read
      memState     : in  std_logic_vector(1 downto 0)    -- state of mem

      );
end memHierarchy;

architecture memHier_arch of memHierarchy is

  component dcache port (
    clk      : in  std_logic;
    nReset   : in  std_logic;
    halt     : in  std_logic;
    halt_out : out std_logic;

    dMemRead      : in  std_logic;                       -- CPU side
    dMemWrite     : in  std_logic;                       -- CPU side
    dMemWait      : out std_logic;                       -- CPU side
    dMemAddr      : in  std_logic_vector (31 downto 0);  -- CPU side
    dMemDataRead  : out std_logic_vector (31 downto 0);  -- CPU side
    dMemDataWrite : in  std_logic_vector (31 downto 0);  -- CPU side

    adMemRead      : out std_logic;                       -- arbitrator side
    adMemWrite     : out std_logic;                       -- arbitrator side
    adMemWait      : in  std_logic;                       -- arbitrator side
    adMemAddr      : out std_logic_vector (31 downto 0);  -- arbitrator side
    adMemDataRead  : in  std_logic_vector (31 downto 0);  -- arbitrator side
    adMemDataWrite : out std_logic_vector (31 downto 0);  -- arbitrator side

                                        --bus side
    TxBusOp   : out memBusOp;
    TxBusAddr : out std_logic_vector(31 downto 0);
    TxBusResp : out memBusResp;
    TxBusData : out std_logic_vector(63 downto 0);
    RxBusOp   : in  memBusOp;
    RxBusAddr : in  std_logic_vector(31 downto 0);
    RxBusResp : in  memBusResp;
    RxBusData : in  std_logic_vector(63 downto 0)
    );
  end component;

  component icache port(
    clk, nrst : in  std_logic;
    tag_in    : in  std_logic_vector(25 downto 0);
    data_in   : in  std_logic_vector(31 downto 0);
    data_out  : out std_logic_vector(31 downto 0);
    index_in  : in  std_logic_vector(3 downto 0);
    hit       : out std_logic;
    icache_en : in  std_logic);
  end component;

  component LinkRegister port(
    clk, nReset : in  std_logic;
    lockAddr    : in  std_logic_vector(31 downto 0);
    lockWEN     : in  std_logic;
    busOp       : in  memBusOp;
    busAddr     : in  std_logic_vector(31 downto 0);
    lockOut     : out std_logic_vector(31 downto 0));
  end component;


  component icache_ctrl
    port(
      clk, nrst         : in  std_logic;
      hit               : in  std_logic;
      icache_ren        : in  std_logic;
      addr              : in  std_logic_vector(31 downto 0);
      data_in           : in  std_logic_vector(31 downto 0);
      icacheWait        : in  std_logic;
      tag               : out std_logic_vector(25 downto 0);
      index             : out std_logic_vector(3 downto 0);
      data_out          : out std_logic_vector(31 downto 0);
      addr_out          : out std_logic_vector(31 downto 0);
      cpuWait           : out std_logic;
      icache_memRequest : out std_logic;
      icache_wen        : out std_logic);
  end component;

  component MemoryArbiter
    port
      (
        clk, nReset    : in  std_logic;
        memAddr        : out std_logic_vector(15 downto 0);
        memWriteData   : out std_logic_vector(31 downto 0);
        memWEN         : out std_logic;
        memREN         : out std_logic;
        memReadData    : in  std_logic_vector(31 downto 0);
        memState       : in  std_logic_vector(1 downto 0);
        icacheWait     : out std_logic;  -- icache must wait if 1
        icacheREN      : in  std_logic;  -- icache read request
        icacheAddr     : in  std_logic_vector(31 downto 0);
        icacheReadData : out std_logic_vector(31 downto 0);

        dcacheREN       : in  std_logic;  -- dcache read request
        dcacheWEN       : in  std_logic;  -- dcache write request
        dcacheWait      : out std_logic;  -- dcache must wait if 1
        dcacheAddr      : in  std_logic_vector(31 downto 0);
        dcacheReadData  : out std_logic_vector(31 downto 0);
        dcacheWriteData : in  std_logic_vector(31 downto 0)
        );
  end component;

  signal iMem, dMem : cacheSignal;
  signal iCntrl     : icacheCntrl;

begin  -- memHier_arch

  arb_c : MemoryArbiter port map (
    clk             => clk,
    nReset          => nReset,
    memAddr         => memAddr,
    memWriteData    => memWriteData,
    memWEN          => memWEN,
    memREN          => memREN,
    memReadData     => memReadData,
    memState        => memState,
    icacheWait      => iMem.stall,
    icacheREN       => iMem.rEn,
    icacheAddr      => iMem.addr,
    icacheReadData  => iMem.rData,
    dcacheREN       => dMem.rEn,
    dcacheWEN       => dMem.wEn,
    dcacheWait      => dMem.stall,
    dcacheAddr      => dMem.addr,
    dcacheReadData  => dMem.rData,
    dcacheWriteData => dMem.wData);

  ic_c : icache port map (
    clk       => clk,
    nrst      => nReset,
    tag_in    => iCntrl.tag,
    data_in   => iMem.rData,
    data_out  => iCntrl.rData,
    index_in  => iCntrl.index,
    hit       => iCntrl.hit,
    icache_en => iCntrl.wEn);

  iccntrl_c : icache_ctrl port map (
    clk               => clk,
    nrst              => nReset,
    hit               => iCntrl.hit,
    icache_ren        => iMemRen,
    addr              => iMemAddr,
    data_in           => iCntrl.rData,
    icacheWait        => iMem.stall,
    tag               => iCntrl.tag,
    index             => iCntrl.index,
    data_out          => iMemData,
    addr_out          => iMem.addr,
    cpuWait           => iMemWait,
    icache_memRequest => iMem.rEN,
    icache_wen        => iCntrl.wEn);

  link_c : LinkRegister port map(
    clk      => clk,
    nReset   => nReset,
    lockAddr => lockAddr,
    lockWEN  => lockWEN,
    busOp    => RxBusOp,
    busAddr  => RxBusAddr,
    lockOut  => lockOut
    );
  
  dcache_c : dcache port map(

    clk           => clk,
    nReset        => nReset,
    halt          => halt,
    dMemRead       => dMemRead,
    dMemWrite       => dMemWrite,
    dMemAddr      => dMemAddr,
    dMemDataWrite => dMemDataWrite,
    dMemDataRead  => dMemDataRead,
    dMemWait      => dMemWait,

    adMemRead      => dMem.rEn,
    adMemWrite     => dMem.wEn,
    adMemWait      => dMem.stall,
    adMemAddr      => dMem.addr,
    adMemDataRead  => dMem.rData,
    adMemDataWrite => dMem.wData,

    TxBusOp   => TxBusOp,
    TxBusAddr => TxBusAddr,
    TxBusResp => TxBusResp,
    TxBusData => TxBusData,
    RxBusOp   => RxBusOp,
    RxBusAddr => RxBusAddr,
    RxBusResp => RxBusResp,
    RxBusData => RxBusData,
    halt_out  => halt_out
    );





end memHier_arch;

